import { ArkFile, ArkNamespace, Stmt } from 'arkanalyzer';
import { ArkClass } from "arkanalyzer/lib/core/model/ArkClass";
import { StmtMatcher, StmtMatcherCallback } from '../Matchers';

export function matchStmt(arkFiles: ArkFile[], matchers: [StmtMatcher, StmtMatcherCallback][]): void {
    for (let arkFile of arkFiles) {
        iterateIr(arkFile, matchers);
    }
}

function iterateIr(arkFile: ArkFile, matchers: [StmtMatcher, StmtMatcherCallback][]): void {
    for (const ns of arkFile.getAllNamespacesUnderThisFile()) {
        iterateNamespace(arkFile, ns, matchers);
    }
    for (const clazz of arkFile.getClasses()) {
        iterateClass(arkFile, clazz, matchers);
    }
}

function iterateNamespace(arkFile: ArkFile, ns: ArkNamespace, matchers: [StmtMatcher, StmtMatcherCallback][]): void {
    for (const childNs of ns.getAllNamespacesUnderThisNamespace()) {
        iterateNamespace(arkFile, childNs, matchers);
    }
    for (const clazz of ns.getClasses()) {
        iterateClass(arkFile, clazz, matchers);
    }
}

function iterateClass(arkFile: ArkFile, clazz: ArkClass, matchers: [StmtMatcher, StmtMatcherCallback][]): void {
    clazz.getMethods().forEach(method => {
        method.getCfg()?.getStmts().forEach(stmt => {
            matchStmtNode(arkFile, stmt, matchers);
        })
    })
}

function matchStmtNode(arkFile: ArkFile, node: Stmt, matchers: [StmtMatcher, StmtMatcherCallback][]): void {
    for (const [matcher, callback] of matchers) {
        if (matcher.match(node)) {
            callback(node, arkFile);
        }
    }
}